/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.web.formmetadata.service;

import com.inspur.edp.i18n.resource.api.II18nResourceDTManager;
import com.inspur.edp.i18n.resource.api.metadata.ResourceItem;
import com.inspur.edp.i18n.resource.api.metadata.ResourceItemCollection;
import com.inspur.edp.i18n.resource.api.metadata.ResourceMetadata;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.lcm.metadata.api.entity.I18nResource;
import com.inspur.edp.lcm.metadata.api.entity.MetadataHeader;
import com.inspur.edp.lcm.metadata.api.exception.MetadataNotFoundException;
import com.inspur.edp.lcm.metadata.api.service.MetadataService;
import com.inspur.edp.web.common.customexception.WebCustomException;
import com.inspur.edp.web.common.entity.ResultCode;
import com.inspur.edp.web.common.entity.ResultMessage;
import com.inspur.edp.web.common.io.FileUtility;
import com.inspur.edp.web.common.logger.WebLogger;
import com.inspur.edp.web.common.metadata.MetadataGetterParameter;
import com.inspur.edp.web.common.metadata.MetadataTypeEnum;
import com.inspur.edp.web.common.metadata.MetadataUtility;
import com.inspur.edp.web.common.serialize.SerializeUtility;
import com.inspur.edp.web.common.utility.StringUtility;
import com.inspur.edp.web.formmetadata.metadata.formdom.FormDOM;
import com.inspur.edp.web.formmetadata.metadata.FormMetadataContent;
import com.inspur.edp.web.formmetadata.metadata.FormMetadataContentService;
import com.inspur.edp.web.formmetadata.i18n.constant.I18nResourceConstant;
import com.inspur.edp.web.formmetadata.replication.FormMetadataReplicator;
import com.inspur.edp.web.formmetadata.replication.ProjectInformationManager;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import io.iec.edp.caf.i18n.framework.api.language.EcpLanguage;
import io.iec.edp.caf.i18n.framework.api.language.ILanguageService;

import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author guozhiqi
 */
public class FormMetataService {
    public static void synchronizeLanuagePackage(String formMetadataFileName, String formMetadataPath) {
        // (1) 获取表单元数据
        GspMetadata formMetadata = MetadataUtility.getInstance().getMetadataWithDesign(formMetadataFileName, formMetadataPath);
        // (2) 查找到关联的资源元数据
        GspMetadata currentResourceMetadata = getRefResourceMetadata(formMetadata.getHeader().getId(), formMetadataPath);

        // (3) 同步资源元数据上的语言包到表单元数据
        synchronizeLanuagePackage(formMetadata, currentResourceMetadata);
    }

    /**
     * 生成表单关联的中文资源元数据
     */
    public static void reSaveFormIfResourceNotExists(GspMetadata formMetadata, String baseFormPath) {
        List<I18nResource> resourceList = getFormResourceWithMetaData(formMetadata, I18nResourceConstant.ZH_CHS, baseFormPath);
        if (resourceList == null || resourceList.isEmpty()) {
            // 调用保存表单元数据接口，间接生成资源元数据
            MetadataService metadataService = SpringBeanUtils.getBean(MetadataService.class);
            metadataService.saveMetadata(formMetadata, Paths.get(formMetadata.getRelativePath()).resolve(formMetadata.getHeader().getFileName()).toString());
        }
    }

    /**
     * 根据表单元数据获取对应的资源列表
     *
     * @param metadata     元数据信息*
     * @param language     语言列表
     * @param baseFormPath 传递的基础表单的路径 针对组合表单，传递的也是基础表单的路径
     */
    public static List<I18nResource> getFormResourceWithMetaData(GspMetadata metadata, String language, String baseFormPath) {
        II18nResourceDTManager resourceDtManager = SpringBeanUtils.getBean(II18nResourceDTManager.class);
        // 当前语言未生效
        try {
            List<I18nResource> resourceList = resourceDtManager.getI18nResource(metadata, language, baseFormPath);
            // 按语言进行过滤
            if (resourceList != null && resourceList.size() > 0) {
                resourceList = resourceList
                        .stream()
                        .filter((t) -> language.equals(t.getLanguage()))
                        .collect(Collectors.toList());
            }
            return resourceList;
        } catch (MetadataNotFoundException ex) {
            WebLogger.Instance.warn(ex.getMessage() + ex.getStackTrace());
        } catch (Exception ex) {
            // 排除掉找不到对应的资源文件的异常
            String fileNotFoundException = "java.io.FileNotFoundException";
            if (ex.getMessage() != null && ex.getMessage().contains(fileNotFoundException)) {
                WebLogger.Instance.warn(ex.getMessage());
            } else {
                WebLogger.Instance.error(ex);
                throw ex;
            }
        }
        return null;
    }

    /**
     * 同步资源元数据的语言包到表单元数据
     */
    private static void synchronizeLanuagePackage(GspMetadata targetFormMetadata, GspMetadata sourceResourceMetadata) {
        // (1) 从资源元数据中获取语言
        String currentLanguage = "en";
        // (2) 同步到表单元数据
        ResourceMetadata resourceMetadataContent = (ResourceMetadata) sourceResourceMetadata.getContent();
        ResourceItemCollection<ResourceItem> resourceItemCollection = resourceMetadataContent.getStringResources();

        FormMetadataContent formMetadataContent = (FormMetadataContent) targetFormMetadata.getContent();
        FormDOM formContent = FormMetadataContentService.getInstance().getFormContent(formMetadataContent);
        HashMap<String, HashMap<String, String>> ctrlLangs = formContent.getModule().getCtrlLangs();


        HashMap<String, String> chosenLaguagePackage = ctrlLangs.get(currentLanguage);
        HashMap<String, String> updatedChosenLaguagePackage = new HashMap<>(chosenLaguagePackage);
        for (Map.Entry<String, String> item : chosenLaguagePackage.entrySet()) {
            String key = item.getKey();
            boolean existSameKey = false;
            for (ResourceItem resourceItem : resourceItemCollection) {
                if (Objects.equals(resourceItem.getId(), item.getKey())) {
                    updatedChosenLaguagePackage.put(key, resourceItem.getValue());
                    existSameKey = true;
                    break;
                }
            }

            if (!existSameKey) {
                updatedChosenLaguagePackage.remove(key);
            }
        }
        ctrlLangs.put(currentLanguage, updatedChosenLaguagePackage);

        FormMetadataContentService.getInstance().setFormContent(formMetadataContent, formContent);

        // 回写表单元数据
        MetadataService metadataService = SpringBeanUtils.getBean(MetadataService.class);
        metadataService.saveMetadata(targetFormMetadata, targetFormMetadata.getRelativePath() + FileUtility.DIRECTORY_SEPARATOR_CHAR + targetFormMetadata.getHeader().getFileName());
    }

    private static List<MetadataHeader> getRefResourceMetadataHeaderCollection(String formMetadataId, String formMetadataPath) {
        MetadataService metadataService = SpringBeanUtils.getBean(MetadataService.class);
        return metadataService.getResourceMetadata(formMetadataId, formMetadataPath);
    }

    private static GspMetadata getRefResourceMetadata(String formMetadataId, String formMetadataPath) {
        List<GspMetadata> resourceMetadataList = getRefResourceMetadataList(formMetadataId, formMetadataPath);
        if (resourceMetadataList == null || resourceMetadataList.size() <= 0) {
            return null;
        }

        // 一个表单元数据仅能关联一个资源元数据
        return resourceMetadataList.get(0);
    }

    private static List<GspMetadata> getRefResourceMetadataList(String formMetadataId, String formMetadataPath) {
        List<MetadataHeader> resourceMetadataHeaderCollection = getRefResourceMetadataHeaderCollection(formMetadataId, formMetadataPath);

        // 获取资源元数据
        return getResourceMetadata(resourceMetadataHeaderCollection, formMetadataPath);
    }

    private static ArrayList<GspMetadata> getResourceMetadata(List<MetadataHeader> resourceMetadataHeaderList, String formMetadataPath) {
        if (resourceMetadataHeaderList == null || resourceMetadataHeaderList.size() <= 0 || StringUtility.isNullOrEmpty(formMetadataPath)) {
            return null;
        }

        ArrayList<GspMetadata> resourceMetadataList = new ArrayList<>();
        for (MetadataHeader resouceMetadataHeader : resourceMetadataHeaderList) {
            String resouceMetadataFileName = resouceMetadataHeader.getFileName();
            GspMetadata resourceMetadata = MetadataUtility.getInstance().getMetadataWithDesign(resouceMetadataFileName, formMetadataPath);
            if (resourceMetadata != null) {
                resourceMetadataList.add(resourceMetadata);
            }
        }

        return resourceMetadataList;
    }

    /**
     * 导出语言包
     */
    public static void exportLanguagePackage(String formMetadataFileName, String formMetadataPath) {
        // (1) 获取表单元数据
        GspMetadata formMetadata = MetadataUtility.getInstance().getMetadataWithDesign(formMetadataFileName, formMetadataPath);
        exportLanguagePackage(formMetadata);
    }

    /**
     * 导出语言包
     */
    public static void exportLanguagePackage(GspMetadata formMetadata) {
        if (formMetadata == null) {
            return;
        }

        FormMetadataContent formMetadataContent = (FormMetadataContent) formMetadata.getContent();
        FormDOM formDOM = FormMetadataContentService.getInstance().getFormContent(formMetadataContent);

        // 从表单文档中提取出语言包并保存为JSON文件
        HashMap<String, HashMap<String, String>> ctrlLangs = formDOM.getModule().getCtrlLangs();
        String ctrlLangsStr = SerializeUtility.getInstance().serialize(ctrlLangs, false);
        String formMetadataFileName = formMetadata.getHeader().getFileName();
        String formMetadataPath = formMetadata.getRelativePath();

        String languagePackageFileName = formMetadataFileName.replace(".frm", "_frm") + ".json";
        String languagePackageAbsoluteStoragePath = MetadataUtility.getInstance().getAbsolutePath(formMetadataPath);
        FileUtility.writeFile(languagePackageAbsoluteStoragePath, languagePackageFileName, ctrlLangsStr);
    }

    /**
     * 同步本地语言包
     */
    public static void synchronizeLocalLanuagePackage(String formMetadataFileName, String formMetadataPath) {
        GspMetadata formMetadata = MetadataUtility.getInstance().getMetadataWithDesign(formMetadataFileName, formMetadataPath);
        synchronizeLocalLanuagePackage(formMetadata);
    }

    /**
     * 同步本地语言包
     */
    public static void synchronizeLocalLanuagePackage(GspMetadata formMetadata) {
        HashMap<String, HashMap<String, String>> localLanguagePackage = getLocalLanguagePackage(formMetadata.getHeader().getFileName(), formMetadata.getRelativePath());

        synchronizeLocalLanuagePackage(formMetadata, localLanguagePackage);
    }

    private static HashMap<String, HashMap<String, String>> getLocalLanguagePackage(String formMetadataFileName, String formMetadataPath) {
        String languagePackageFileName = formMetadataFileName.replace(".frm", "_frm") + ".json";
        String languagePackageAbsoluteStoragePath = MetadataUtility.getInstance().getAbsolutePath(formMetadataPath);
        String localLanguagePackageFullPath = Paths.get(languagePackageAbsoluteStoragePath).resolve(languagePackageFileName).toString();
        String localLanguagePackageStr = FileUtility.readAsString(localLanguagePackageFullPath);

        HashMap<String, HashMap<String, String>> temp = new HashMap<>();
        return SerializeUtility.getInstance().deserialize(localLanguagePackageStr, temp.getClass());
    }

    private static void synchronizeLocalLanuagePackage(GspMetadata targetFormMetadata, HashMap<String, HashMap<String, String>> sourceLocalLanguagePackage) {
        FormMetadataContent formMetadataContent = (FormMetadataContent) targetFormMetadata.getContent();
        FormDOM formContent = FormMetadataContentService.getInstance().getFormContent(formMetadataContent);

        // TODO: 优化更新算法
        // 更新语言包
        formContent.getModule().setCtrlLangs(sourceLocalLanguagePackage);

        // 更新表单元数据内容
        FormMetadataContentService.getInstance().setFormContent(formMetadataContent, formContent);

        // 更新表单元数据
        MetadataService metadataService = SpringBeanUtils.getBean(MetadataService.class);
        metadataService.saveMetadata(targetFormMetadata, Paths.get(targetFormMetadata.getRelativePath()).resolve(targetFormMetadata.getHeader().getFileName()).toString());
    }

    public static List<EcpLanguage> getEnabledLanguageList() {
        ILanguageService languageService = SpringBeanUtils.getBean(ILanguageService.class);
        return languageService.getEnabledLanguages();
    }

    public static List<EcpLanguage> getBuiltinLanguageList() {
        ILanguageService languageService = SpringBeanUtils.getBean(ILanguageService.class);
        return languageService.getBuiltinLanguages();
    }

    public static List<EcpLanguage> getAllLanguageList() {
        ILanguageService languageService = SpringBeanUtils.getBean(ILanguageService.class);
        return languageService.getAllLanguages();
    }

    public static ResultMessage<String> replicateForm(String sourceMetadataId, String sourceMetadataRelativePath, String targetMetadataCode, String targetMetadataName, String targetProjectName) {
        if (StringUtility.isNullOrEmpty(sourceMetadataId) || StringUtility.isNullOrEmpty(sourceMetadataRelativePath)) {
            WebLogger.Instance.error("待复制表单元数据ID或路径为空。请检查前端请求参数是否正常。", FormMetataService.class.getName());
            throw new WebCustomException("待复制表单元数据ID或路径为空。请检查前端请求参数是否正常。");
        }
        if (StringUtility.isNullOrEmpty(targetMetadataCode) || StringUtility.isNullOrEmpty(targetMetadataName)) {
            throw new WebCustomException("目标元数据Code或Name不能为空");
        }

        //根据当前表单元数据id 获取对应的元数据信息
        // 判断当前表单元数据是否不存在
        if (!MetadataUtility.getInstance().isMetaDataExistsWithMetadataIDAndPathWithDesign(sourceMetadataRelativePath, sourceMetadataId)) {
            return ResultCode.info("待复制的表单元数据不存在，请确认该元数据是否已被删除。");
        }
        MetadataGetterParameter metadataGetterParameter = MetadataGetterParameter.getNewInstance(sourceMetadataId, sourceMetadataRelativePath, MetadataTypeEnum.Frm);
        metadataGetterParameter.setTargetMetadataNotFoundMessage("表单复制失败，待复制的表单元数据不存在，请确认该元数据是否已被删除。");

        GspMetadata sourceFormMetadata = MetadataUtility.getInstance().getMetadataWithDesign(metadataGetterParameter);
        if (sourceFormMetadata == null) {
            throw new WebCustomException("表单复制，获取元数据为空。待获取元数据ID是：" + sourceMetadataId);
        }

        // 获取待复制元数据所在工程名称
        String sourceProjectName = ProjectInformationManager.getProjectName(sourceFormMetadata);
        if (StringUtility.isNullOrEmpty(sourceProjectName)) {
            throw new WebCustomException("待复制元数据所在工程的工程名为空。待复制元数据ID是：" + sourceMetadataId);
        }

        FormMetadataReplicator formMetadataReplicator = new FormMetadataReplicator();
        return formMetadataReplicator.replicate(sourceFormMetadata, sourceProjectName, targetMetadataCode, targetMetadataName, targetProjectName);
    }
}
